// 公共配置
// 基于node 的使用commonjs规范的语法
let path=require('path')
//webpack中只要是使用插件都需要使用node语法引入进来
let HtmlWbpackPlugin=require('html-webpack-plugin') // HtmlWbpackPlugin 首字母大写说明是个类
let CleanWebpackPlugin=require('clean-webpack-plugin')
let webpack=require('webpack') //这是webpack自带的功能直接引入进行
// let ExtractTextWebpackPlugin=require('extract-text-webpack-plugin')
// ExtractTextWebpackPlugin在以后的webpack版本中有望被miniCssExtractPlugin替代
let MiniCssExtractPlugin=require('mini-css-extract-plugin')
//去除用不到的css样式减少项目体积性能优化
let PurifyCSSPlugin=require('purifycss-webpack')
// let CopyWebpackPlugin=require('copy-webpack-plugin') //拷贝插件
let OptimizeCss=require('optimize-css-assets-webpack-plugin')
let UglifyJsPlugin = require("uglifyjs-webpack-plugin")
let glob=require('glob')
// let cssExtract=new ExtractTextWebpackPlugin({
//     filename:'css/css.css',
//     disable:true // 为了开发阶段的便利先禁用，上线在去掉
// })
// let lessExtract=new ExtractTextWebpackPlugin({
//     filename:'css/less.css',
//     disable:true
// })
module.exports={ // 首先必须要导出一个对象固定配置
     optimization:{// 优化项，只有 mode:'production'的时候会执行development的时候不会执行
         minimizer:[
            new UglifyJsPlugin({
                cache: true, //是否用缓存
                parallel: true,//是否用并发打包（一起压缩多个）
                sourceMap: true // es6转换为es5的调试
              }),
             new OptimizeCss() // 进行css压缩
         ]
     },
    //entry有三种写法
    entry:'./src/index.js', //入口(通过这个文件去打包把资源整合出去)
    // 如果js文件之间没有使用导出引入来关联起来但是都想引入到html中此时
    // entry:['./src/index.js','./src/a.js'],
    //多页面配多入口多出口，不同的html文件中需要不同的js文件
    // entry:{
    //     index:'./src/index.js',
    //     a:'./src/a.js'
    // },
    output:{
       filename:'build.[hash:8].js', // 打包出的文件名，加一个hash是清除缓存的区分每一次打包出来的文件,8表示只是显示8位数的hash值
        // filename:'[name].[hash].js', //多页面配多入口多出口 不同的出口对应不同的文件名
        //<script type="text/javascript" src="build.7e3575ce6de6eaa5e843.js?7e3575ce6de6eaa5e843"></script>
        path:path.resolve(__dirname,'build'), // 这里必须是一个绝对路径,node的这个resolve方法能生成一个绝对路径来console.log(path.resolve(__dirname,'build'))，把打包出来的文件放到这个文件夹下面
        // publicPath:'htpp://www.xxx.com' 把所有资源引用前都加上这个地址前缀，如果只想把图片放到cdn上其他资源不放那么那个放入cdn就单独给谁配置publicPath
    }, // 出口
    devServer:{
        contentBase:'./build', //让打包出来的服务直接读取根目录下的build目录下的文件(服务默认是在内存中启动的本地中的build目录下找不到的东西会到内存build目录中查找)
        port:3000, //端口号
        compress:true, //服务器压缩
        open:true, //自动打开浏览器
        hot:true, //热更新所需配置
        //解决跨域的三种方案
        // proxy:{//方案1配置代理来解决跨域
        //     '/api':{
        //         target:'http://localhost:3000',//项目只要是/api开头的请求路径都替换成http://localhost:4000
        //         pathRewrite: {
        //             '/api': ''
        //           }
        //     }
            
        // }
        //方案2单纯模拟数据，不过要后台提供服务，这里的app就是后台的服务
        // before(app){
        //     app.get('/user',(req,res)=>{
        //         res.json({name:'zs1'})
        //     })
        // }
        //方案3把webpack放到后台来启动
    }, // 开发服务器
    plugins:[
        new webpack.DefinePlugin({
            DEV:"'development'" //这里配置的是全局变量DEV在项目的任何文件里使用的时候双引号会被去掉所以要两层引号不然会报development变量没定义或者JSON.stringfy('development')
        }),
        // new CopyWebpackPlugin([ //Error: [copy-webpack-plugin] patterns must be an array表示传参必须是一个数组
        //     {
        //         from:'./src/doc', // 把doc里面的文件原封不动的拷到打包文件夹build下的public文件夹下
        //         to:'public'
        //     }
        // ]),
        // new ExtractTextWebpackPlugin({
        //     filename:'css/index.css' // 把所有的css和less编译成css的文件都抽离到css文件夹下生成一个index.css文件
        // }),
        new MiniCssExtractPlugin({
            filename:'css/index.css'
        }),
        //css作css的抽离，less作less的抽离
        // cssExtract,
        // lessExtract,
        new webpack.NamedModulesPlugin(), // 可以打印出跟新文件的路径
        new webpack.HotModuleReplacementPlugin(), //热更新所需配置
        // new webpack.ProvidePlugin({ // 引入jquery的方式1项目的每个模块注入jquery不需要import $ from 'jquery'引入如页面中import $ from 'jquery'引入了就相当于引入了两次
        //jquery那么项目的打包时候体积会增大
        //     $:'jquery'
        // }),
       // new CleanWebpackPlugin(['./build']), //把打包过程中需要删除的文件放入数组里或者写一个正则来匹配要删的所有文件 
        //CleanWebpackPlugin先清除之前的build然后HtmlWbpackPlugin再打包出来新的build
        new HtmlWbpackPlugin({ // 传入一个options配置对象 具体配置查看www.npmjs.com/package/html-webpack-plugin(查那个包就使用那个包名字)
            template:'./src/index.html', //表示打包的时候去这个地方找到html文件引入打包好的js文件并放入build文件夹下
            title:'王家勇', // 这些属性都可以在html文件中通过ejs语法取到
            hash:true //加一个hash是清除缓存的区分每一次打包出来的文件
            //<script type="text/javascript" src="build.7e3575ce6de6eaa5e843.js?7e3575ce6de6eaa5e843"></script>?后面的内容就是这里的hash配置生成的
            // minify:{ // 对html文件进行压缩的配置
            //     removeAttributeQuotes:true,// 字面意思移除属性双引号
            //     collapseWhitespace:true //去掉空格折叠成一行
            // }
        }),
        new PurifyCSSPlugin({
            paths: glob.sync(path.join(__dirname, 'src/*.html')) // 这里必须是一个绝对路径（去src下面找到所有的html文件把里面没有用到的样式都删除掉）
          }),
        // 多页面配多入口多出口 都是以index为模版打包出两个html文件，chunks表示当前html文件引入的js文件是谁
        // new HtmlWbpackPlugin({
        //     filename:'a.html',
        //     template:'./src/index.html', 
        //     title:'王家勇',
        //     hash:true,
        //     chunks:['index']
        // }),
        // new HtmlWbpackPlugin({
        //     filename:'b.html',            
        //     template:'./src/index.html', 
        //     title:'王家勇',
        //     hash:true,
        //     chunks:['a']            
        // })
        // bannerPlugin 内置的进行版权声明的插件
        new webpack.BannerPlugin('王家勇书写于2019/1/17的webpack配置代码'), 
        //优化
        new webpack.IgnorePlugin(/\.\/locale/,/moment/), //IgnorePlugin内置的插件语法是两个正则表示忽略moment包中引入的locale文件
        new webpack.DllReferencePlugin({
            manifest:path.resolve(__dirname,'build','manifest.json') // 当使用import引入react的时候不进行打包，先去build下找manifest.json
            // 找到通过manifest这个任务清单去查找变量对应的文件中的内容（变量是通过html文件中的<script src="/_dll_react.js"></script>引入的）
        })
    ], // webpack分为两大类各种lodar和plugins(插件的配置)
    // externals:{ // 引入jquery的方式2,页面中不需要import $ from 'jquery'引入就算import $ from 'jquery'引入了也不会进行打包
    //     jquery:'$'
    // },
    //源码映射以下4种（帮助我们调试源代码），执行npm run start 的时候会生成.map文件出错了会标识当前报错的行和列
    // devtool:'source-map',
    // devtool:'eval-source-map', 不会产生map文件
    // devtool:'cheap-module-source-map', 不会产生列的报错但是是一个单独的映射文件
    // devtool:'cheap-module-eval-source-map', 不会产生列的报错集成在打包后的文件中
    // mode:'development', //webpack4新增的，表示打包过后的文件是上线生产模式（production会压缩）还是本地开发模式 （development不会压缩）
    resolve:{
        modules:[path.resolve('node_modules')],//commonjs查找规范表示只是在当前目录下进行查找
        extensions:['.js','.css','.json','.vue'], // 通过import引入文件的时候省略文件后缀名的配置（查找顺序）
        mainFields:['style','main']//这样import 'bootstrap'引入bootstrap这种库的时候默认先去找node_modules下脚本文件中找main下对应的js文件才去找style下的css文件，这里改变查找顺序先
        //去找style下的css文件找不到再去找main下对应的js文件如果找到就返回
    }, //webpack的解析规则在这里进行配置
    // watch: true, // 项目代码一发生变化就自动打包代码
    // watchOptions:{
    //     poll:1000,// 每秒问1000次是否需要打包
    //     aggregateTimeout:500,// 停止在项目中写东西后500毫秒开始打包
    //     ignored:/node_modules/ //排除不需要监控的文件
    // },
    module:{ // 模块通过配置以下的规则来进行处理解析
        //noParse:/jquery/,//优化项，打包的时候忽略jquery中的依赖提高打包效率
        rules:[
            // {
            //     test:/\.html$/,
            //     use:'html-withimg-loader'
            // },
            // {
            //     test:/\.(png|jpg|gif)$/,
            //     use:{
            //         loader:'url-loader',
            //         options:{
            //             limit:200*1024, //小于200k的图片都使用url-loader转化成base64大于200k的都使用file-loader来产生真实的图片
            //             outputPath:'/img/',//打包好的图片都放到img目录下
            //             publicPath:'htpp://www.xxx.com'// 所有图片前面都加上一个地址前缀（可以把资源放到cdn下提高资源加载的效率和速度项目优化）
            //         }
            //     }
            // },
            // {
            //     test:require.resolve('jquery'),// 引入jquery的方式3
            //     use:'expose-loader?$!jquery' // 这个规则表示只要引用了jquery的地方使用expose-loader把jquery暴露到全局用$来展示，页面中直接import $ from 'jquery'引用就行了
            // },
            // {
            //     test:/\.js$/,use:
            //     {
            //     loader:'eslint-loader',
            //     options:{
            //         enforce:'pre' //由于loader默认从右向左向下往上执行，由于有两个匹配js的规则所以加 enforce:'pre'参数让'eslint-loader'js语法校验在'babel-loader'js语法解析之前执行
            //     }
            //     }
            // },
            {
                test:/\.js$/,use:{
                loader:'babel-loader',//babel相关都是进行js语法的处理
                options:{
                    presets:[ // 语法转换需要的映射配在这里
                        '@babel/preset-env', // 大插件的集合 es6转换为es5
                        "@babel/preset-react" // 解析react得语法
                    ],
                    plugins:[ 
                        // '@babel/plugin-proposal-class-properties' // 处理class这种更高级的语法的
                        ["@babel/plugin-proposal-decorators", { "legacy": true }],
                        ["@babel/plugin-proposal-class-properties", { "loose" : true }],
                        "@babel/plugin-syntax-dynamic-import",
                        "@babel/plugin-transform-runtime"// 打包编译的时候还需要@babel/runtime会往生产环境注入一些脚本
                    ]
                }
            },
            // 只去编译src下的文件排除node_modules下面的文件
            include:path.resolve(__dirname,'src'), 
            exclude:/node_modules/
        },
            // {test:/\.css$/,use:[ //css-loader本身自带热跟新的功能，但是把所有的css抽离成一个模块通过link标签的方式引入到html后就没有了所以需要安装extract-text-webpack-plugin@next(webpack4.0需要加上@next)
            //     // 这个插件以后有望被mini-css-extract-plugin取代
            //     {loader:'style-loader',
            //      options:{insertAt:'top'} //插入到html页面的顶部，让html中style中样式的优先级大于打包出来插入页面的style的优先级
                //},
            //     {loader:'css-loader'} 
            // ]},
            // {test:/\.less$/,use:[ // 规则是从右往左写，以less结尾的文件把less解析成css，css解析成模块，把css模块插入到style标签中
            //     {loader:'style-loader'},
            //     {loader:'css-loader'}, 
            //     {loader:'less-loader'}
            // ]}
            //ExtractTextWebpackPlugin可以把所有的css抽离成一个模块通过link标签的方式引入，不用放到style标签中所以style-loader不需要了
            // {test:/\.css$/,use:ExtractTextWebpackPlugin.extract({
            //     use:[
            //          {loader:'css-loader'}, 
            //          {loader:'postcss-loader'}
            //      ]
            //  })},
            //  {test:/\.less$/,use:ExtractTextWebpackPlugin.extract({
            //      use:[
            //           {loader:'css-loader'},
            //           {loader:'less-loader'}, // 安装less-loader还需要安装less，less-loader调用less来解析less文件
            //           {loader:'postcss-loader'}
            //       ]
            //   })}
              {
                test:/\.css$/,
                use:[
                     MiniCssExtractPlugin.loader,//把css抽离到指定文件中
                     {loader:'css-loader'}, 
                     {loader:'postcss-loader'}
                 ]
             },
             {
                 test:/\.less$/,
                 use:[
                      MiniCssExtractPlugin.loader,//把less抽离到指定文件中如果不写 MiniCssExtractPlugin.loader表示不抽离
                      //{loader:'style-loader'}, //把样式插到style中
                      {loader:'css-loader'},
                      {loader:'less-loader'}, // 安 less-loader还需要安装less，less-loader调用less来解析less文件
                      {loader:'postcss-loader'}
                  ]
              }
            //css和less分别抽离到不同的文件中
            //   {test:/\.css$/,use:cssExtract.extract({
            //      fallback:'style-loader', // 开发的时候插入到html的style标签中上线的时候去掉
            //      use:[
            //           {loader:'css-loader'} 
            //       ]
            //   })},
            //   {test:/\.less$/,use:lessExtract.extract({
            //      fallback:'style-loader',                 
            //       use:[
            //            {loader:'css-loader'},
            //            {loader:'less-loader'}
            //        ]
            //    })}
        ]
    }// 配置一些模块加载的（加载css,js这些）
}
// 执行npm run start和npm run build都会进行打包前者是在内存中后者是生成实体文件（一个是开发环境一个是生产环境执行的配置相同的也有不同的）
// webpack中怎么配置开发服务器 安装webpack-dev-server
// webpack插件，把html文件打包到build文件夹下并且html中自动引入打包好的js文件
// webpack自带的优化，1.tree-shaking(通过import引入文件的时候，在生成环境下会自动去除没被使用用的代码)比如引入一个工具包但是只是使用了里面的两个
// 方法那么没有使用的方法在打包的时候会被删除掉
// 2.scope hosting作用域提升（简化代码，去除冗余代码）例如
// let a=1
// let b=1
// let c=1
// let d=a+b+c
// console.log(d) webpack打包的时候会自动帮你生成console.log(1+1+1)

// 在一个框架中使用生命周期，就是在不同的阶段执行不同的函数，把框架实例传出去，其他地方得到实力以后可以预先绑定（发布订阅模式）